package aapt

import (
	"archive/zip"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type Package struct {
	Name                     string
	VersionName              string
	VersionCode              int
	PlatformBuildVersionName string
	SdkVersion               int
	TargetSdkVersion         int
	Application_label_zh_CN  string
	Application_label        string
	Application_icon         string
	Permission               []string
}

func GetAppInfo(apkfile string) (res Package) {
	t1 := time.Now()
	var appinfo = make(map[string]string, 10)
	var permission = make([]string, 0, 20)
	if exec.Command("which", "aapt").Run() != nil {
		fmt.Errorf("command aapt not found, skipping")
	}
	out, err := exec.Command("aapt", "d", "badging", apkfile).CombinedOutput()
	aaptGot := string(out)
	if err != nil {
		panic(err)
	}
	info := strings.Split(aaptGot, "\n")
	for key := range info {
		tmp := info[key]
		reg1 := regexp.MustCompile(`^package:`)
		reg2 := regexp.MustCompile(`^uses-permission:`)
		reg3 := regexp.MustCompile(`^application:`)
		reg4 := regexp.MustCompile(`^sdkVersion:`)
		reg5 := regexp.MustCompile(`^targetSdkVersion:`)
		reg6 := regexp.MustCompile(`^application-label-zh-CN:`)
		if reg1.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `package: `)
			for _, value := range strings.Split(tmp, ` `) {
				q, h := replace(value)
				if strings.HasPrefix(q, "name") {
					appinfo["package"] = h
				} else {
					appinfo[q] = h
				}
			}
		} else if reg2.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `uses-permission: `)
			_, h := replace(tmp)
			if strings.HasPrefix(h, "android.permission.") {
				permission = append(permission, h)
			}
		} else if reg3.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `application: `)
			for _, value := range strings.Split(tmp, `' `) {
				q, h := replace(value)
				if strings.Contains(q, "label") {
					appinfo["application-label"] = h
				} else {
					appinfo["application-"+q] = h
				}
			}
		} else if reg4.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `sdkVersion: `)
			q, h := replace(tmp)
			appinfo[q] = h
		} else if reg5.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `targetSdkVersion: `)
			q, h := replace(tmp)
			appinfo[q] = h

		} else if reg6.MatchString(tmp) {
			tmp = strings.TrimPrefix(tmp, `application-label-zh-CN: `)
			q, h := replace(tmp)
			appinfo[q] = h

		} else {
			continue
		}
	}
	//for key, value := range appinfo {
	//	println(key, value)
	//}
	res.VersionName = appinfo["versionName"]
	vCode, _ := strconv.Atoi(appinfo["versionCode"])
	res.VersionCode = vCode
	res.Name = appinfo["package"]
	res.Application_icon = appinfo["application-icon"]
	res.Permission = permission
	res.Application_label = appinfo["application-label"]
	res.Application_label_zh_CN = appinfo["application-label-zh-CN"]
	res.PlatformBuildVersionName = appinfo["platformBuildVersionName"]
	sdkVer, _ := strconv.Atoi(appinfo["sdkVersion"])
	res.SdkVersion = sdkVer
	tarSdkVer, _ := strconv.Atoi(appinfo["targetSdkVersion"])
	res.TargetSdkVersion = tarSdkVer
	elapsed := time.Since(t1)
	fmt.Println("Read the APK file elapsed: ", elapsed)
	return res
}

func DeApkIcon(zipFile, filterFile string) (icon string, err error) {
	t1 := time.Now()
	ext := path.Ext(filterFile)
	fileName := strings.TrimSuffix(path.Base(zipFile), path.Ext(zipFile)) + ext
	fileName = filepath.Join(getDir(zipFile), fileName)

	readerZip, err := zip.OpenReader(zipFile)
	if err != nil {
		return fileName, err
	}
	defer readerZip.Close()
	for _, file := range readerZip.File {
		if file.FileHeader.Name == filterFile {
			rc, err := file.Open()
			if err != nil {
				return fileName, err
			}
			w, err := os.Create(fileName)
			if err != nil {
				return fileName, err
			}
			defer w.Close()
			_, err = io.Copy(w, rc)
			if err != nil {
				return fileName, err
			}
			w.Close()
			rc.Close()
			break
		}
	}
	elapsed := time.Since(t1)
	fmt.Println("Extract icon file elapsed: ", elapsed)
	return fileName, nil
}
func getDir(path string) string {
	return subString(path, 0, strings.LastIndex(path, "/"))
}
func subString(str string, start, end int) string {
	rs := []rune(str)
	length := len(rs)

	if start < 0 || start > length {
		panic("start is wrong")
	}

	if end < start || end > length {
		panic("end is wrong")
	}

	return string(rs[start:end])
}
func replace(str string) (q, h string) {
	if len(strings.Split(str, `=`)) > 1 {
		q = strings.Split(str, `=`)[0]
		h = strings.Split(str, `=`)[1]
	} else if len(strings.Split(str, `:`)) > 1 {
		q = strings.Split(str, `:`)[0]
		h = strings.Split(str, `:`)[1]
	}
	return q, strings.Replace(h, `'`, ``, -1)
}
